home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
17 Bit Software 6: Level 6
/
17 Bit - Level 6 (1998)(Epic Marketing)[!].iso
/
quartz
/
q0528.dms
/
q0528.adf
/
romable.doc
< prev
next >
Wrap
Text File
|
1991-02-02
|
16KB
|
438 lines
romable/romable romable/romable
ROMABLE.DOC
GENERATING ROMABLE FIRMWARE
REFERENCES
Please refer to the following DCC options:
-pi generate position independant code. All code references
forced to PC-relative
-pr generate residentable position independant code. Unless
-mw is specified A4 relative addressing is used for data
items. All code references forced to PC-relative.
-ma specify that initialized data + bss will be hardwired to
a known address
-mw specify that initialized data + bss will be hardwired to
a known address and all of data + bss occurs somewhere
within the first 32KBytes of the address space
(0x0000-0x7FFF). Also allows DICE to use A4 as a register
variable.
-ms const items go into EPROM in local cases
-mS const items go into EPROM in local and external cases
The following documentation may appear confusing, but only because so
many possibilities exist when one intends to put code in ROM. When you
are in doubt, it is usually a good idea to write a small test source
file, compile it, link it with symbols, and then look at the resulting
executable with DOBJ.
MAKING ROMABLE PROGRAMS
DICE has the capability to generate ROMABLE programs. That is, program
binaries that you can use to directly burn an EPROM. When generating
ROMABLE code you have more data model options available to you. The
basic idea of ROMd code is as follows:
________________
FIXED ADDRESS = EPROM | |
| 68000 vectors | const data objects
|----------------|
| CODE |
|----------------|
| const DATA | string constants and other
| | const items, stays in eprom.
|----------------|
| read-only copy |
| of initialized | this is copied to a working
| data | RAM copy by the reset code
|________________|
________________
FIXED ADDRESS = RAM | run-time copy | (copied from EPROM by startup)
| of initialized |
| data |
|----------------| (cleared by EPROM startup)
| run-time BSS |
|________________|
From the above you have two basic choices in terms of where your
RUN-TIME DATA is based. If your RAM exists in low-memory
(0x0000-0x7FFF) you may choose to compile your code to use the
ABSOLUTE-WORD addressing mode. This modes takes the same space as the
A4-RELATIVE addressing mode yet does not require use of the A4 register
and, in fact, the A4 register will then be available for use as a
register variable.
If you have minimal RAM in low-memory or your DATA+BSS is larger than
32KBytes (yes, that's 32KBytes people, not 64KBytes), then you will
have to choose either the formal large-data model or the A4-relative
small data model. If you initialized data is over 64KBytes you can
still use the small-data model for most objects by using the __far
keyword judiciously.
NOTE: in all cases you can allocate or generate points for any ram
location, this just refers to accesses of declared variables! Pointers
are always 32 bits.
model options advantages disadvantages
absolute-word -mw -ms no need for A4 low 32KBytes only
A4 available as
reg variable
small-data -ma -ms RAM can be anywhere requires A4
must use __geta4
large-data -ma -mD -ms RAM can be anywhere code is larger
libs must all be
large-data
CODE MODEL
The CODE MODEL is normally left at PC-relative and should not present a
problem.
CONST DATA
You want to use the -ms option or even the -mS option (see DCC.DOC for
the differences). This will place all string constants in EPROM and
IN THE CODE SEGMENT, thus this initialized data will NOT take up space
in RAM. Any 'const' initialized data will be placed in the code segment
and thus in EPROM. Any non-const initialized data will be copied from
EPROM into RAM by your reset-startup code.
Any tables that you declare that you will never modify should be
declared const so they reside in EPROM and do not take up space in RAM.
On the otherhand, if your EPROM is running 6 wait states and your RAM
is running 0 you might consider not using 'const'.... assuming you have
a lot of RAM.
When your code is less than 32KBytes big you can use -pi or -pr and
should definitely use -mS. When your code is larger than 32KBytes you
cannot use -mS unless you are absolutely positive pc-relative const
data references do not exceed the word-relative range.
RESET VECTOR, DATA MODEL SETUP
If your EPROM is mapped into low memory on boot you can declare a vector
table by declaring a CONST LONG array as the first data object in the
first object module that you link to create the executable:
const long ROMVectorTable[] = {
InitialSSP,
ResetVector,
.
.
.
};
Remember, this must be the first data declaration in the first object
module!!! If you are using the A4-RELATIVE small-data model you must
qualify your ResetVector with the __geta4 type qualifier to set up A4.
In most cases you will want ResetVector to point to some assembly which
initializes your RAM DATA & BSS before calling C code. The assembly
normally looks like this (this would be the second object in the link):
; RESET exception, copy initialized data to RAM and clear
; BSS area before calling rom_main()
;
; Assumes less than 256KBytes of data and 256KBytes of BSS
xref __DATA_BAS ; linker generated symbols
xref __ABSOLUTE_BAS
xref __DATA_LEN
xref __BSS_LEN
xref _rom_main
_ResetVector
lea __DATA_BAS,A0 ; ROM data
lea __ABSOLUTE_BAS,A1 ; RAM data
move.w #__DATA_LEN,D0 ; long words of data
bra trentry
trloop move.l (A0)+,(A1)+ ; copy EPROM copy to run-time
trentry dbf D0,trloop ; RAM copy.
move.w #__BSS_LEN,D0 ; long words of BSS (follows data)
moveq.l #0,D1
bra trbentry
trbloop move.l D1,(A1)+ ; clear run-time RAM
trbentry dbf D0,trbloop
jmp _rom_main(pc)
Where rom_main() is your C main routine qualified with __geta4 (if you
are using the A4-RELATIVE data model). Any special items, such as
the EPROM getting mapped at reset, must be dealt with as well, usually
before the reset code sets up the run-time enviroment.
If you are using the ABSOLUTE-WORD data model DO NOT USE __GETA4!
Specifically, the -mw option TELLS DICE THAT A4 IS FREE FOR USE AS A
NORMAL REGISTER VARIABLE. This gives you an extra register variable if
you haven't guessed!
EXAMPLE PROGRAM
Assume the above assembly module has been assembled and is called
'romc.o'. The following C program is called 'test.c'. In all cases
the code may start anywhere.
Also, in all cases note that ROMC.O is specified AFTER test in the
DCC line (that also serves as the link line). This is because for
a standalone product we want our CONST data object that is the
ROM VECTOR TABLE to be first. Of course, if you put the ROM VECTOR
TABLE in ROMC.A instead of TEST.C then ROMC.A would go first. To
put the ROM VECTOR TABLE in ROMC.A it should be the first data
object declarations (dc.l's) in the CODE segment.
(1) SMALL-DATA-MODEL
extern void TrapReset();
extern char SSp[512];
const long RomVectors[] = { (long)SSp, (long)TrapReset };
char SSp[512]; /* our supervisor stack in BSS */
__geta4 void
rom_main()
{
short i;
for (;;) {
for (i = 0; i < 10000; ++i) {
<do something here with i>
}
}
}
note, ram can be beyond 64K
v
COMPILE: dcc test.c romc.o -ma 0x10000 -o t:test -r -v -lrom
romable t:test -o t:test.bin -D 0x10000 -C 0x0
burn eprom using test.bin
(2) ABSOLUTE WORD DATA MODEL
The source code is the same except you do not need __geta4. Here
I am assuming RAM starts at, say, 0x2000.
void
rom_main()
{
...
}
COMPILE: dcc test.c romc.o -mw 0x2000 -o t:test -r -lrom
romable t:test -o t:test.bin -D 0x2000 -C 0x0
burn eprom using test.bin
(3) ABSOLUTE LONG DATA MODEL
The source code is the same as for (2). Here the RAM may start
anywhere (also true in (1)).
COMPILE: dcc test.c romc.o -ma 0x10080 -o t:test -r -lrom
romable t:test -o t:test.bin -D 0x10080 -C 0
burn eprom using test.bin
(4) EXAMPLE OF EPROM INITIALLY MAPPED AT 0x0000 BUT REMAPPABLE TO
SOMEWHERE ELSE
In this case the assembly, ROMC.A, must relocate the EPROM back
to where it should be before initializing the data segment. Here
your initial CONST data is the EPROM VECTOR TABLE, and your initial
non-CONST INITIALIZED data (because BSS gets stuck after all
initialized data) will be your RAM VECTOR TABLE.
In this example I assume that RAM will be mapped into 0x0000-
by the time rom_main() gets called. Compilation depends on the
data model. The example below uses the ABSOLUTE WORD data model.
extern void TrapReset();
extern char SSp[512];
const long RomVectors[] = { (long)SSp, (long)TrapReset };
long RamVectors[] = { (long)SSp, (long)TrapReset, ... };
char SSp[512]; /* our supervisor stack in BSS */
void
rom_main()
{
...
}
In this compilation example I am assuming the RAM will be at 0x0000 and
the ROM, say, at 0x20000 (above the 64KBmark)
COMPILE: dcc test.c romc.o -mw 0 -o t:test -r -lrom
romable t:test -o t:test.bin -D 0 -C 0x20000
burn eprom using test.bin
USING ROM.LIB
ROM.LIB is generated from LIB/FILES.ROM3LIB and contains those modules
from C.LIB that do not declare any variables and are position
independant. Modules in the library are entirely position independant.
If you use library calls instead of macros in <ctype.h> for ctype
functions those are position independant as well ... they use
pc-relative to access the lookup tables (which are declared const).
Nothing in ROM.LIB declares any data variables. The idea is to link
your code with ROM.LIB instead of C.LIB to ensure that incompatible
routines are never included by mistake.
Warning: If you want position independant code you must compile with
-pi or -mS, especially when accessing <ctype.h> macros. Accessing
<ctype.h> macros and not using either the above options will result in
absolute-code references to ctype's lookup tables.
------------------------------------------------------------------------
MAKING RAM MODULES
Generating a binary image for an executable that is meant to run from
RAM instead EPROM is relatively easy. In many cases you want only a
single copy of the data (instead of two copies as in EPROM modules..
the permanent initialized data in EPROM and the run-time data+bss in
RAM). This means that the program is not-reentrant... once an
initialized data variable is modified it stays modified. If this is
not desireable you can use the same methods as were described for
making EPROM code combined with methods (see LIB/AMIGA/C_PR.A) to
allocate the data space run-time.
If you want to generate resident style modules use the small-data model
version in the previous section 'MAKING ROMABLE PROGRAMS' and simply
apply the concept of downloading such a module into RAM instead of ROM.
It is especially easy when the code is completely position independant
because your firmware does not have to deal with relocation at all.
This section describes standalone modules with UNsharable code because
the code is completely position independant and references only one set
of data.
________________
ANY ADDRESS IN RAM |startup |
| CODE |
|----------------|
| initialized |
| data |
|----------------|
| |
| BSS |
|----------------|
The code uses a single PC-relative reference to find the start of the
data, then generates the A4 register to point to the data section.
NOT A SINGLE 32-BIT REFERENCE EXISTS.
WARNING: The module has only one set of data. Once initialized data
is modified it stays modified through multiple invocations of the module
The advantage of using a position independant module is obvious... you
can copy it to any point in ram as-is and then call it! For small
68000 boxes with limited memory this is definite plus as it greatly
simplifies the loading mechanism.
To create a 100% relocatable module, the code must be less than 32K
and the data less than 64K. You must use the -pi option when compiling
all source modules, when running dlink, and when running ROMABLE.
The -pi option, amoung other things, puts the __ABSOLUTE_BAS and
__DATA_BAS linker symbols in the code section. Actually, dlink puts
the entire program into a single CODE hunk!
dcc -c test.c -pi
dlink -pi rampi.o test.o -lrom -o test
romable test -o test.bin -pi
RAMPI.A is something you have to write, but you do have a template.
Take a look at LIB/AMIGA/C_PI.A as an example (also note that
LIB/AMIGA/X.A is also required). Remember that the autoinit sections
must be entirely supported though not necessarily the autoexit sections,
it depends on your application.
USING ROM.LIB
ROM.LIB is generates from LIB/FILES.ROM3LIB and contains compiler
support routines that do not require any RAM. Modules in the library
are entirely position independant. If you use library calls instead
of macros in <ctype.h> for ctype functions those are position
independant as well ... they use pc-relative to access the lookup
tables (which are declared const).
Nothing in ROM.LIB declares any data variables. The idea is to link
your code with ROM.LIB instead of C.LIB to ensure that incompatible
routines are never included (instead you get an undefined symbol error
from the linker when you make a mistake).
Warning: If you want position independant code you must compile with
-pi or -mS, especially when accessing <ctype.h> macros.
------------------------------------------------------------------------
ROMABLE exeFile -o outFile [-o outFile2] -C addr -D addr -pi
addr: decimal, 0octal, or 0xHEX
Romable generates a binary image for an executable compiled under DICE
and is normally used to generate a ROMABLE raw binary output file.
exeFile input executable linked with dlink
-o outFile output binary (unformatted -- raw). If TWO -o options
are specified the two output files will have even bytes
and odd bytes respectively, which is what you need when
you must program two eproms (one on the LSB data lines
and one on the MSB data lines)
example: -o out1 result: 01 02 03 04
example: -o out1 -o out2 result (out1): 01 03
result (out2): 02 04
-C addr code start address, 0octal, decimal, or 0xHEX
-D addr data start address, 0octal, decimal, or 0xHEX
-DC place actual data+bss just after code (i.e. the
result is intended to be downloaded into RAM, there
is no duplicate data in this case).
'-D addr' is not specified in this case
-pi generate a position independant module. Neither
-C or -D are specified in this case, and ROMABLE
will warn you have any absolute references.
Note that your custom startup code determines how much of __autoinit
and __autoexit is to be supported. Note especially that __autoinit0
MUST BE SUPPORTED because DICE will generate __autoinit0 sections to
handle 32 bit data relocations run-time.
ROMABLE generates a raw output file or files with the EPROM code first,
and initialized data after the main code (still in EPROM) which, as
has already been described, will be copied to RAM on reset by your
startup routine.
This startup-copying of initialized data and clearing of BSS makes it
extremely easy to use DICE to generate ROMED applications without
having to deal with major porting considerations.